package main

import (
	"context"
	"fmt"
	"time"

	amqp "github.com/rabbitmq/amqp091-go"
)

const exchange = "go_ex"

func main() {
	conn, err := amqp.Dial("amqp://root:123456@192.168.1.2:5672/")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	ch, err := conn.Channel()
	if err != nil {
		panic(err)
	}
	defer ch.Close()

	// 创建exchange
	err = ch.ExchangeDeclare(
		exchange,
		"fanout", // kind 就是管理工具的type
		true,     // durable
		false,    // autoDelete
		false,    // internal 是否是内部的exchange。内部的exchange,外部是无法给它发送消息的。只有内部exchange才有消息走动。
		false,    // noWait
		nil,      // args
	)
	if err != nil {
		panic(err)
	}

	go subscribe(conn, exchange)
	go subscribe(conn, exchange)

	i := 0
	for {
		i++
		err := ch.PublishWithContext(
			context.Background(),
			exchange,
			"",    // key
			false, // mandatory
			false, // immediate
			amqp.Publishing{
				Body: []byte(fmt.Sprintf("message %d", i)),
			},
		)
		if err != nil {
			fmt.Println(err.Error())
		}
		time.Sleep(200 * time.Millisecond)
	}
}

func subscribe(conn *amqp.Connection, ex string) {
	ch, err := conn.Channel()
	if err != nil {
		panic(err)
	}
	defer ch.Close()

	// 创建队列 这个就是一旦没人收就自动删除，服务器重启它也会没有。
	q, err := ch.QueueDeclare(
		"",    // name 不设置name系统会自动给我们分配一个
		false, // durable 这个只是说要订阅exchange，没说要怎么给它保留
		true,  // autoDelete 我们对这个Queue不是很关心它的生命周期，我们不需要它活多久，只是需要拿着Queue去订阅exchange
		false, // exlusive
		false, // noWait
		nil,   // args
	)
	if err != nil {
		panic(err)
	}
	defer ch.QueueDelete( // 不希望这个Queue占据太多资源
		q.Name,
		false, // ifUnused 是否没人用才删除(false就不管有没有人用都要删除)
		false, // ifEmpty 是否空才删除
		false, // noWait
	)

	// 绑定exchange
	err = ch.QueueBind(
		q.Name,
		"",    // key
		ex,    // exchange
		false, // noWait
		nil,   // args
	)
	if err != nil {
		panic(err)
	}

	consume("c", ch, q.Name)
}

func consume(consumer string, ch *amqp.Channel, q string) {
	msgs, err := ch.Consume(
		q,
		consumer, // consumer
		true,     // autoAck
		false,    // exclusive
		false,    // noLocal
		false,    // noWait
		nil,      // args
	)
	if err != nil {
		panic(err)
	}

	for msg := range msgs {
		fmt.Printf("%s: %s\n", consumer, msg.Body)
	}
}
